// 共享文件检索工具 - 主服务器
// 提供HTTP API接口和静态文件服务

const express = require('express');
const cors = require('cors');
const path = require('path');
const fs = require('fs');
const config = require('./config/config');
const FileScanner = require('./modules/fileScanner');
const DataProcessor = require('./modules/dataProcessor');

class FileSearchServer {
  constructor() {
    this.app = express();
    this.scanner = new FileScanner();
    this.dataProcessor = new DataProcessor();
    this.currentScanId = null;
    this.isScanning = false;
    this.autoScanInterval = null;
    
    this.setupMiddleware();
    this.setupRoutes();
  }

  /**
   * 设置中间件
   */
  setupMiddleware() {
    // 启用CORS
    this.app.use(cors({
      origin: config.server.corsOrigin,
      credentials: true
    }));

    // 解析JSON请求体
    this.app.use(express.json({ limit: '10mb' }));
    this.app.use(express.urlencoded({ extended: true }));

    // 静态文件服务（前端构建后的文件）
    this.app.use(express.static(path.join(__dirname, '../frontend/dist')));
    this.app.use(express.static(path.join(__dirname, '../frontend/dist/public')));

    // 请求日志
    this.app.use((req, res, next) => {
      console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
      next();
    });
  }

  /**
   * 设置路由
   */
  setupRoutes() {
    // API路由
    this.app.use('/api', this.createApiRoutes());
    
    // 前端路由（SPA支持）
    this.app.get('*', (req, res) => {
      res.sendFile(path.join(__dirname, '../frontend/dist/index.html'));
    });

    // 错误处理中间件
    this.app.use(this.errorHandler.bind(this));
  }

  /**
   * 创建API路由
   */
  createApiRoutes() {
    const router = express.Router();

    // 获取文件索引
    router.get('/index', this.getFileIndex.bind(this));
    
    // 触发文件扫描
    router.post('/scan', this.startFileScan.bind(this));
    
    // 获取扫描状态
    router.get('/scan/status/:scanId?', this.getScanStatus.bind(this));
    
    // 停止扫描
    router.post('/scan/stop', this.stopFileScan.bind(this));
    
    // 搜索文件
    router.get('/search', this.searchFiles.bind(this));
    
    // 刷新索引
    router.post('/refresh', this.refreshIndex.bind(this));
    
    // 获取系统状态
    router.get('/status', this.getSystemStatus.bind(this));
    
    // 获取配置信息
    router.get('/config', this.getConfig.bind(this));

    // 文件操作相关接口
    router.get('/file/download/:fileId', this.downloadFile.bind(this));
    router.get('/file/preview/:fileId', this.previewFile.bind(this));
    router.get('/file/info/:fileId', this.getFileInfo.bind(this));

    return router;
  }

  /**
   * 获取文件索引
   */
  async getFileIndex(req, res) {
    try {
      console.log('请求获取文件索引...');
      
      const indexData = await this.dataProcessor.loadJsonFile();
      
      if (!indexData) {
        return res.json({
          success: false,
          message: '索引文件不存在，请先进行文件扫描',
          data: null
        });
      }

      res.json({
        success: true,
        message: '索引数据获取成功',
        data: indexData
      });

    } catch (error) {
      console.error('获取索引时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '获取索引失败: ' + error.message,
        data: null
      });
    }
  }

  /**
   * 开始文件扫描
   */
  async startFileScan(req, res) {
    try {
      if (this.isScanning) {
        return res.json({
          success: false,
          message: '扫描正在进行中，请等待完成',
          scanId: this.currentScanId
        });
      }

      const { path: scanPath, force = false } = req.body;
      const targetPath = scanPath || config.scan.targetPath;

      console.log(`开始文件扫描: ${targetPath}`);
      
      // 生成扫描ID
      this.currentScanId = 'scan_' + Date.now();
      this.isScanning = true;

      // 异步执行扫描
      this.performFileScan(targetPath)
        .then(() => {
          console.log('文件扫描完成');
          this.isScanning = false;
        })
        .catch(error => {
          console.error('文件扫描失败:', error);
          this.isScanning = false;
        });

      res.json({
        success: true,
        message: '文件扫描已启动',
        scanId: this.currentScanId
      });

    } catch (error) {
      console.error('启动扫描时发生错误:', error);
      this.isScanning = false;
      
      res.status(500).json({
        success: false,
        message: '启动扫描失败: ' + error.message,
        scanId: null
      });
    }
  }

  /**
   * 执行文件扫描
   */
  async performFileScan(targetPath) {
    try {
      // 执行扫描
      const scanResult = await this.scanner.startScan(targetPath);
      
      // 处理扫描结果并保存
      await this.dataProcessor.processScanResult(scanResult);
      
      console.log('扫描和数据处理完成');
      
    } catch (error) {
      console.error('执行扫描时发生错误:', error);
      throw error;
    }
  }

  /**
   * 获取扫描状态
   */
  getScanStatus(req, res) {
    try {
      const requestedScanId = req.params.scanId;
      
      // 如果指定了scanId但不匹配当前扫描，返回未找到
      if (requestedScanId && requestedScanId !== this.currentScanId) {
        return res.json({
          success: false,
          message: '指定的扫描任务不存在',
          data: null
        });
      }

      const progress = this.scanner.getScanProgress();
      
      res.json({
        success: true,
        message: '扫描状态获取成功',
        data: {
          scanId: this.currentScanId,
          isScanning: this.isScanning,
          ...progress
        }
      });

    } catch (error) {
      console.error('获取扫描状态时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '获取扫描状态失败: ' + error.message,
        data: null
      });
    }
  }

  /**
   * 停止文件扫描
   */
  stopFileScan(req, res) {
    try {
      const force = req.body?.force || req.query?.force === 'true';
      
      // 先检查扫描器内部状态
      const scannerProgress = this.scanner.getScanProgress();
      const serverThinking = this.isScanning;
      const scannerThinking = scannerProgress.isScanning;
      
      console.log(`停止扫描请求 - 强制模式: ${force}, 服务器状态: ${serverThinking}, 扫描器状态: ${scannerThinking}`);
      
      // 检测状态不一致
      if (serverThinking !== scannerThinking) {
        console.warn(`检测到状态不一致：服务器=${serverThinking}, 扫描器=${scannerThinking}`);
        // 强制修复状态不一致
        this.forceResetScanState();
        return res.json({
          success: true,
          message: '检测到状态不一致，已强制重置扫描状态'
        });
      }
      
      // 如果都认为没有扫描且不是强制模式，返回错误
      if (!force && !serverThinking && !scannerThinking) {
        return res.json({
          success: false,
          message: '当前没有正在进行的扫描任务'
        });
      }

      // 停止扫描器
      this.scanner.stopScan();
      
      // 如果是强制模式，强制重置所有状态
      if (force) {
        this.forceResetScanState();
        console.log('强制重置扫描状态完成');
      } else {
        this.isScanning = false;
      }

      res.json({
        success: true,
        message: force ? '扫描状态已强制重置' : '扫描停止请求已发送'
      });

    } catch (error) {
      console.error('停止扫描时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '停止扫描失败: ' + error.message
      });
    }
  }

  /**
   * 强制重置扫描状态（解决状态不一致问题）
   */
  forceResetScanState() {
    try {
      console.log('开始强制重置扫描状态...');
      
      // 1. 重置服务器主状态
      this.isScanning = false;
      this.currentScanId = null;
      
      // 2. 强制重置扫描器状态
      this.scanner.forceReset();
      
      console.log('扫描状态强制重置完成');
    } catch (error) {
      console.error('强制重置扫描状态失败:', error);
    }
  }

  /**
   * 搜索文件
   */
  async searchFiles(req, res) {
    try {
      const {
        keyword = '',
        type = 'all',
        searchType = 'all',
        limit = config.ui.resultsPerPage,
        pathContext = ''  // 新增：路径上下文
      } = req.query;

      if (!keyword.trim()) {
        return res.json({
          success: false,
          message: '搜索关键词不能为空',
          data: []
        });
      }

      console.log(`搜索文件: "${keyword}", 类型: ${type}, 路径上下文: ${pathContext}`);

      // 执行搜索
      const fileIds = this.dataProcessor.search(keyword, {
        searchType,
        fileType: type,
        maxResults: parseInt(limit),
        pathContext  // 传递路径上下文
      });

      // 获取完整的文件信息
      const indexData = await this.dataProcessor.loadJsonFile();
      if (!indexData) {
        return res.json({
          success: false,
          message: '索引数据不存在，请先进行文件扫描',
          data: []
        });
      }

      let matchedFiles = this.dataProcessor.getFilesByIds(fileIds, indexData.files);

      // 如果有路径上下文，进一步过滤结果
      if (pathContext) {
        matchedFiles = matchedFiles.filter(file => 
          file.path.includes(pathContext) || file.parent.includes(pathContext)
        );
      }

      res.json({
        success: true,
        message: pathContext 
          ? `在路径 "${pathContext}" 下找到 ${matchedFiles.length} 个匹配文件`
          : `找到 ${matchedFiles.length} 个匹配文件`,
        data: matchedFiles,
        total: matchedFiles.length,
        pathContext: pathContext
      });

    } catch (error) {
      console.error('搜索文件时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '搜索失败: ' + error.message,
        data: []
      });
    }
  }

  /**
   * 刷新索引
   */
  async refreshIndex(req, res) {
    try {
      if (this.isScanning) {
        return res.json({
          success: false,
          message: '扫描正在进行中，无法刷新索引'
        });
      }

      console.log('开始刷新索引...');
      
      // 重新加载索引文件
      const indexData = await this.dataProcessor.loadJsonFile();
      
      if (!indexData) {
        return res.json({
          success: false,
          message: '索引文件不存在，请先进行文件扫描'
        });
      }

      // 重新构建搜索索引
      this.dataProcessor.buildSearchIndex(indexData.files);

      res.json({
        success: true,
        message: '索引刷新成功',
        data: {
          totalFiles: indexData.files.length,
          totalFolders: indexData.folders.length,
          refreshTime: new Date().toISOString()
        }
      });

    } catch (error) {
      console.error('刷新索引时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '刷新索引失败: ' + error.message
      });
    }
  }

  /**
   * 获取系统状态
   */
  async getSystemStatus(req, res) {
    try {
      const indexStats = this.dataProcessor.getIndexStats();
      const scanProgress = this.scanner.getScanProgress();

      res.json({
        success: true,
        message: '系统状态获取成功',
        data: {
          server: {
            uptime: process.uptime(),
            memory: process.memoryUsage(),
            version: '1.0.0'
          },
          scan: {
            isScanning: this.isScanning,
            currentScanId: this.currentScanId,
            ...scanProgress
          },
          index: indexStats,
          config: {
            targetPath: config.scan.targetPath,
            autoRefresh: config.scan.autoRefreshInterval
          }
        }
      });

    } catch (error) {
      console.error('获取系统状态时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '获取系统状态失败: ' + error.message,
        data: null
      });
    }
  }

  /**
   * 获取配置信息
   */
  getConfig(req, res) {
    try {
      res.json({
        success: true,
        message: '配置信息获取成功',
        data: {
          scan: {
            targetPath: config.scan.targetPath,
            excludePatterns: config.scan.excludePatterns,
            fileTypes: config.scan.fileTypes
          },
          ui: config.ui,
          server: {
            port: config.server.port,
            host: config.server.host
          }
        }
      });

    } catch (error) {
      console.error('获取配置时发生错误:', error);
      res.status(500).json({
        success: false,
        message: '获取配置失败: ' + error.message,
        data: null
      });
    }
  }

  /**
   * 错误处理中间件
   */
  errorHandler(error, req, res, next) {
    console.error('服务器错误:', error);
    
    res.status(500).json({
      success: false,
      message: '服务器内部错误',
      error: process.env.NODE_ENV === 'development' ? error.message : '请联系管理员'
    });
  }

  /**
   * 启动服务器
   */
  start() {
    const port = config.server.port;
    const host = config.server.host;

    this.app.listen(port, host, async () => {
      console.log('\n' + '='.repeat(50));
      console.log('🚀 共享文件检索工具服务器已启动');
      console.log('='.repeat(50));
      console.log(`📡 服务器地址: http://${host}:${port}`);
      console.log(`📁 扫描目标: ${config.scan.targetPath}`);
      console.log(`💾 索引文件: ${config.scan.indexFile}`);
      console.log('='.repeat(50));
      console.log('📋 可用的API端点:');
      console.log('   GET  /api/index        - 获取文件索引');
      console.log('   POST /api/scan         - 开始文件扫描');
      console.log('   GET  /api/scan/status  - 获取扫描状态');
      console.log('   GET  /api/search       - 搜索文件');
      console.log('   POST /api/refresh      - 刷新索引');
      console.log('   GET  /api/status       - 获取系统状态');
      console.log('='.repeat(50));
      console.log('✨ 服务器就绪，等待请求...\n');
      
      // 启动后自动检查和初始化
      await this.initializeAfterStart();
    });

    // 优雅关闭处理
    process.on('SIGINT', () => {
      console.log('\n📴 收到关闭信号，正在优雅关闭服务器...');
      
      if (this.isScanning) {
        console.log('⏹️  停止正在进行的扫描...');
        this.scanner.stopScan();
      }
      
      if (this.autoScanInterval) {
        console.log('⏹️  停止定时扫描任务...');
        clearInterval(this.autoScanInterval);
      }
      
      console.log('👋 服务器已关闭');
      process.exit(0);
    });
  }

  /**
   * 服务器启动后的初始化
   */
  async initializeAfterStart() {
    try {
      console.log('🔍 检查索引文件状态...');
      
      // 检查索引文件是否存在
      const indexData = await this.dataProcessor.loadJsonFile();
      
      if (!indexData) {
        console.log('📋 索引文件不存在，启动首次自动扫描...');
        // 延迟3秒后开始首次扫描，给前端时间加载
        setTimeout(async () => {
          await this.performAutoScan('初始化扫描');
        }, 3000);
      } else {
        console.log('✅ 索引文件已存在，检查是否需要更新...');
        
        // 检查索引文件年龄
        const lastUpdate = new Date(indexData.metadata.lastUpdate);
        const now = new Date();
        const ageInHours = (now - lastUpdate) / (1000 * 60 * 60);
        
        if (ageInHours > 24) {
          console.log(`⏰ 索引文件已过期 (${ageInHours.toFixed(1)}小时)，启动更新扫描...`);
          setTimeout(async () => {
            await this.performAutoScan('更新扫描');
          }, 5000);
        } else {
          console.log(`✅ 索引文件较新 (${ageInHours.toFixed(1)}小时前更新)`);
        }
      }
      
      // 启动定时扫描任务
      this.startAutoScanSchedule();
      
    } catch (error) {
      console.error('初始化时发生错误:', error);
    }
  }

  /**
   * 启动定时扫描计划
   */
  startAutoScanSchedule() {
    // 每24小时自动扫描一次（每天最多1次）
    const interval = 24 * 60 * 60 * 1000; // 24小时
    
    this.autoScanInterval = setInterval(async () => {
      if (!this.isScanning) {
        console.log('⏰ 定时自动扫描开始...');
        await this.performAutoScan('定时扫描');
      } else {
        console.log('⏰ 定时扫描跳过（已有扫描在进行中）');
      }
    }, interval);
    
    console.log(`⏰ 定时扫描已启动，间隔: ${interval / (1000 * 60 * 60)}小时（每天最多1次）`);
  }

  /**
   * 执行自动扫描
   */
  async performAutoScan(reason = '自动扫描') {
    try {
      if (this.isScanning) {
        console.log(`⏩ ${reason}跳过（已有扫描在进行中）`);
        return;
      }

      console.log(`🚀 开始${reason}...`);
      
      this.currentScanId = 'auto_scan_' + Date.now();
      this.isScanning = true;

      // 执行扫描
      await this.performFileScan(config.scan.targetPath);
      
      console.log(`✅ ${reason}完成`);
      
    } catch (error) {
      console.error(`❌ ${reason}失败:`, error);
    } finally {
      this.isScanning = false;
    }
  }
  
  /**
   * 文件下载
   */
  async downloadFile(req, res) {
    try {
      const { fileId } = req.params;
      
      console.log(`请求下载文件: ${fileId}`);
      
      // 获取文件信息
      const fileInfo = await this.getFileInfoById(fileId);
      if (!fileInfo) {
        return res.status(404).json({
          success: false,
          message: '文件不存在'
        });
      }
      
      const filePath = fileInfo.fullPath;
      
      // 安全检查：验证文件路径
      if (!this.validateFilePath(filePath)) {
        return res.status(403).json({
          success: false,
          message: '文件路径无效'
        });
      }
      
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        return res.status(404).json({
          success: false,
          message: '文件不存在于磁盘'
        });
      }
      
      // 设置响应头
      const encodedFileName = encodeURIComponent(fileInfo.name);
      res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodedFileName}`);
      res.setHeader('Content-Type', 'application/octet-stream');
      res.setHeader('Content-Length', fileInfo.size);
      
      // 流式传输文件
      const fileStream = fs.createReadStream(filePath);
      
      fileStream.on('error', (error) => {
        console.error('文件读取错误:', error);
        if (!res.headersSent) {
          res.status(500).json({
            success: false,
            message: '文件读取失败'
          });
        }
      });
      
      fileStream.pipe(res);
      
      console.log(`文件下载开始: ${fileInfo.name}`);
      
    } catch (error) {
      console.error('文件下载失败:', error);
      if (!res.headersSent) {
        res.status(500).json({
          success: false,
          message: '文件下载失败: ' + error.message
        });
      }
    }
  }
  
  /**
   * 文件预览
   */
  async previewFile(req, res) {
    try {
      const { fileId } = req.params;
      
      console.log(`请求预览文件: ${fileId}`);
      
      // 获取文件信息
      const fileInfo = await this.getFileInfoById(fileId);
      if (!fileInfo) {
        return res.status(404).json({
          success: false,
          message: '文件不存在'
        });
      }
      
      const filePath = fileInfo.fullPath;
      
      // 安全检查
      if (!this.validateFilePath(filePath)) {
        return res.status(403).json({
          success: false,
          message: '文件路径无效'
        });
      }
      
      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        return res.status(404).json({
          success: false,
          message: '文件不存在于磁盘'
        });
      }
      
      // 根据文件类型设置适当的Content-Type
      const mimeType = this.getMimeType(fileInfo.extension);
      res.setHeader('Content-Type', mimeType);
      res.setHeader('Content-Disposition', `inline; filename*=UTF-8''${encodeURIComponent(fileInfo.name)}`);
      
      // 流式传输文件
      const fileStream = fs.createReadStream(filePath);
      
      fileStream.on('error', (error) => {
        console.error('文件预览错误:', error);
        if (!res.headersSent) {
          res.status(500).json({
            success: false,
            message: '文件预览失败'
          });
        }
      });
      
      fileStream.pipe(res);
      
      console.log(`文件预览开始: ${fileInfo.name}`);
      
    } catch (error) {
      console.error('文件预览失败:', error);
      if (!res.headersSent) {
        res.status(500).json({
          success: false,
          message: '文件预览失败: ' + error.message
        });
      }
    }
  }
  
  /**
   * 获取文件信息
   */
  async getFileInfo(req, res) {
    try {
      const { fileId } = req.params;
      
      console.log(`请求文件信息: ${fileId}`);
      
      // 获取文件信息
      const fileInfo = await this.getFileInfoById(fileId);
      if (!fileInfo) {
        return res.status(404).json({
          success: false,
          message: '文件不存在'
        });
      }
      
      // 检查文件是否存在于磁盘
      const exists = fs.existsSync(fileInfo.fullPath);
      
      res.json({
        success: true,
        message: '文件信息获取成功',
        data: {
          ...fileInfo,
          accessible: exists
        }
      });
      
    } catch (error) {
      console.error('获取文件信息失败:', error);
      res.status(500).json({
        success: false,
        message: '获取文件信息失败: ' + error.message
      });
    }
  }
  
  /**
   * 根据文件ID获取文件信息
   */
  async getFileInfoById(fileId) {
    const indexData = await this.dataProcessor.loadJsonFile();
    if (!indexData || !indexData.files) {
      return null;
    }
    
    return indexData.files.find(file => file.id === fileId);
  }
  
  /**
   * 验证文件路径安全性
   */
  validateFilePath(filePath) {
    // 检查路径是否在允许的目录内
    const normalizedPath = path.normalize(filePath);
    const targetPath = path.normalize(config.scan.targetPath);
    
    return normalizedPath.startsWith(targetPath);
  }
  
  /**
   * 获取文件MIME类型
   */
  getMimeType(extension) {
    const mimeTypes = {
      '.pdf': 'application/pdf',
      '.doc': 'application/msword',
      '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      '.xls': 'application/vnd.ms-excel',
      '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      '.ppt': 'application/vnd.ms-powerpoint',
      '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
      '.jpg': 'image/jpeg',
      '.jpeg': 'image/jpeg',
      '.png': 'image/png',
      '.gif': 'image/gif',
      '.txt': 'text/plain',
      '.md': 'text/markdown',
      '.json': 'application/json',
      '.mp4': 'video/mp4',
      '.mp3': 'audio/mpeg',
      '.zip': 'application/zip',
      '.rar': 'application/x-rar-compressed'
    };
    
    return mimeTypes[extension.toLowerCase()] || 'application/octet-stream';
  }
}

// 启动服务器
const server = new FileSearchServer();
server.start();